xlv.imp.dnd={
	implement:function(){
	},
	method:{
		dnd_properties:{
			dragOnly:false,
			ghost:true,
			ghostElement:null,
			ghostFloat:false,
			ghostHomeXY:[],
			direction:'any',//vertical,horizontal
			_documentEvent:[],
			_dragging:false,
			_startXY:null,
			_lastXY:[],
			offsetXY:[],
			source:null,
			target:null,
			accept:false,
			dragCancel:false
		},
		dnd_enabled:function(enable){
			if(enable)this.addEventHandler('mousedown', '_dnd_chkmousedown');
			else this.removeObserve('mousedown', '_dnd_chkmousedown');
		},
		_dnd_chkmousedown:function(event){
			var p=this.dnd_properties;
			var source=this.dnd_dragable(event);
			p.source=(source)? Object.isElement(source)?source:event.target:null;
			if(p.source){
				p._startXY=[Event.pointerX(event),Event.pointerY(event)];
				p._lastXY=[Event.pointerX(event),Event.pointerY(event)];
				p._timeout=setTimeout((function(){this._dnd_register(event);}).bind(this),10);
				Event.stop(event);
			}
		},
		_dnd_register:function(event){
			var p=this.dnd_properties;
			p._documentEvent=[document.onmousemove, document.onmouseup];			
			document.onmousemove=this._dnd_dragMouseMove.bindAsEventListener(this);
			document.onmouseup=this._dnd_dragMouseUp.bindAsEventListener(this);
		 	this.pauseObserve();
			p.offsetXY=[0,0];
			p.target=null;
			p.accept=false;
			p.dragCancel=false;
			p._dragging=false;
		},
		_dnd_unregister:function(){
			var p=this.dnd_properties;
			if(p._timeout)clearTimeout(p._timeout);
			p._timeout=null;
			document.onmousemove=p._documentEvent[0];
			document.onmouseup=p._documentEvent[1];
			this.dnd_destroyGhost();
			p.source=null;
			p.target=null;
			p.accept=false;
			p._dragging=false;
			this.restoreObserve();
		},
		dnd_createGhost:function(){
			var p=this.dnd_properties;
			if(!p.ghostElement){
				p.ghostElement=document.createElement('div');
				p.ghostElement.appendChild(p.source.cloneNode(true));
				var lt=xlv.desktop.viewportOffset(p.source);
				Element.setStyle(p.ghostElement,{cursor:'default',display:'none',left:lt[0]+'px',top:lt[1]+'px',background:'gray',position:'absolute',zIndex:xlv.sys.zIndexDnd});
				Element.setOpacity(p.ghostElement,0.5);
				xlv.desktop.appendChild(p.ghostElement);
				p.ghostHomeXY=[parseInt(p.ghostElement.style.left),parseInt(p.ghostElement.style.top)];
			}
		},
		dnd_destroyGhost:function(){
			var ghost=this.dnd_properties.ghostElement;
			if(ghost && ghost.parentNode) ghost.parentNode.removeChild(ghost);
			this.dnd_properties.ghostElement=null;
		},
		_dnd_dragMouseMove:function(event){
			Event.stop(event);
			var p=this.dnd_properties;
			if(!p._dragging){
				p._dragging=true;
				if(p.ghost) {
					var ghost=this.dnd_createGhost();
					if(ghost&&Object.isElement(ghost))p.ghostElement=ghost;
				}
				this.dnd_dragStart(event);
			}
			var xy=[Event.pointerX(event), Event.pointerY(event)];
			p.offsetXY=[xy[0]-p._lastXY[0],xy[1]-p._lastXY[1]];
			p._lastXY=xy;
			if(p.ghost && p.ghostElement) {
				p.ghostElement.style.display='';
				var x=parseInt(p.ghostElement.style.left)+((p.direction=='vertical')?0:p.offsetXY[0]);
				var y=parseInt(p.ghostElement.style.top)+((p.direction=='horizontal')?0:p.offsetXY[1]);
				p.ghostElement.style.left=x+'px';
				p.ghostElement.style.top=y+'px';
			}
			/*check hit element*/
			if(!p.dragOnly){
				var target=event.target;
				if(target==p.source) p.accept=false;
				else{
					if(target!=p.target) {
						var xvc=xlv.util.findParent(target,{xlvobject:'*'});
						p.accept=(xvc && typeof xvc.dnd_accept =='function')? xvc.dnd_accept(p.source,target) : false;
					}
				}
				p.target=target;
			}
			/*call override dnd_drag*/
			var cancel=this.dnd_drag(event);
			if(cancel=='cancel') {
				p.dragCancel=true;
				this._dnd_dragMouseUp(event);
			}
		},
		_dnd_dragMouseUp:function(event){
			Event.stop(event);
			var p=this.dnd_properties;
			if(!p._dragging){
				this._dnd_unregister();
				return;
			}
			document.onmousemove=p._documentEvent[0];
			document.onmouseup=p._documentEvent[1];
			/*call back function while move effect*/
			function clean(e){
				var p=this.dnd_properties;
				this.dnd_destroyGhost();
				p._dragging=false;
				this.dnd_dragEnd(e);
				if(p.accept && p.target) {
					var xvc=xlv.util.findParent(p.target,{xlvobject:'*'});
				 	if(xvc) xvc.dnd_drop(e,this);
				}
				p.source=null;
				this.restoreObserve();
			};
			/*decide where to go the ghost*/
			if(p.ghostElement && p.source && p.ghostFloat){
				var lt=p.ghostHomeXY;
				if(p.accept && p.target)lt=xlv.desktop.viewportOffset(p.target);
				if(lt[0]==undefined||lt[1]==undefined)lt=xlv.desktop.viewportOffset(p.source);
				var finish={element:p.ghostElement,style:{left:lt[0],top:lt[1]}};
				finish.finished=clean.bind(this,event);
				xlv.util.styleEffect(finish);
				return;
			}
			else clean.apply(this,[event]);
		},
		/*function overrided by elements*/
		dnd_dragable:function(event){
			return true;
		},
		dnd_dragStart:function(event){
		},
		dnd_drag:function(event){
			return '';
		},
		dnd_dragEnd:function(event){
		},
		dnd_accept:function(source, target){
			var xvc=xlv.util.findParent(source,{xlvobject:'*'});
			if(xvc && xvc.objectName()== this.objectName())return true;
			return false;
		},
		dnd_drop:function(event,drag_dnd_object){
		}
	}
};

